﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Security.AccessControl;
using System.Text;
using System.Threading;
using System.Web;
using Google.GData.Documents;
using Google.GData.Client;
using ICSharpCode.SharpZipLib.Zip;
using mmCore.Classes;
using mmCore.Common;
using mmCore.Interfaces;
using mmXmlDataProvider;

namespace mmGoogleDataProvider
{
    public class GoogleDataProvider: IDataProvider
    {
        private static Tuple<string,string> GetUserAndPass(string arg)
        {
            string[] credentials = arg.Split(new char[] { ':' }, 2);
            if (credentials.Length != 2)
            {
                return null;
            }

            return new Tuple<string, string>(credentials[0], credentials[1]);
        }

        private static AtomEntry GetDataAtomEntry(DocumentsService ds)
        {
            var subQuery = new DocumentsListQuery {Title = Gutils.DataFileName, TitleExact = true};
            var subFeed = ds.Query(subQuery);

            if (subFeed == null || subFeed.Entries == null || subFeed.Entries.Count < 1)
            {
                return null;
            }

            var entry = subFeed.Entries.ToList().OrderByDescending(doc => doc.Updated).First();

            return entry;
        }

        private static string StripTagsCharArray(string source)
        {
            char[] array = new char[source.Length];
            int arrayIndex = 0;
            bool inside = false;

            for (int i = 0; i < source.Length; i++)
            {
                char let = source[i];
                if (let == '<')
                {
                    inside = true;
                    continue;
                }
                if (let == '>')
                {
                    inside = false;
                    continue;
                }
                if (!inside)
                {
                    array[arrayIndex] = let;
                    arrayIndex++;
                }
            }
            return new string(array, 0, arrayIndex);
        }

        #region Implementation of IDataProvider

        public List<Movie> ReadMovies(Stream str)
        {
            try
            {
                var sr = new StreamReader(str);
                var credentials = sr.ReadToEnd();
                var tuple = GetUserAndPass(credentials);
                if(tuple == null)
                {
                    return null;
                }

                var ds = new DocumentsService(Gutils.ServiceName);
                ds.setUserCredentials(tuple.Item1, tuple.Item2);

                var entry = GetDataAtomEntry(ds);
                if(entry == null)
                {
                    var dp = new XmlDataProvider();
                    var ms = new MemoryStream();
                    dp.SaveMovies(ms, new List<Movie>());
                    var b64File = string.Format("{0}.b64.txt", Gutils.TempDataFile);
                    if (ProcessFile(ms, b64File))
                    {
                        ds.UploadDocument(b64File, Gutils.DataFileName);
                        File.Delete(b64File);
                    }
                    return new List<Movie>();
                }

                var fs = ds.Query(new Uri(entry.Content.AbsoluteUri));
                var fsr = new StreamReader(fs);

                var dpr = new XmlDataProvider();
                var content = fsr.ReadToEnd();

                content = StripTagsCharArray(content);
                content = HttpUtility.HtmlDecode(content);
                content = content.Substring(content.LastIndexOf("}") + 1);


                var es = Encoding.UTF8.GetBytes(content);
                var ems = new MemoryStream();
                ems.Write(es, 0, es.Length);
                using(var eds = Gutils.DecodeStream(ems))
                {
                    eds.Seek(0, SeekOrigin.Begin);
                    return dpr.ReadMovies(eds);
                }
            }
            catch (Exception exc)
            {
                ExceptionManager.ReportError(exc);
                return null;
            }
        }

        public bool SaveMovies(Stream str, List<Movie> aMovies)
        {
            var sr = new StreamReader(str);
            var credentials = sr.ReadToEnd();

            var tuple = GetUserAndPass(credentials);
            if (tuple == null)
            {
                return false;
            }

            var ds = new DocumentsService(Gutils.ServiceName);
            ds.setUserCredentials(tuple.Item1, tuple.Item2);

            GetDataAtomEntry(ds).Delete();

            var xdp = new XmlDataProvider();
            var ms = new MemoryStream();
            xdp.SaveMovies(ms, aMovies);
            
            var b64Name = string.Format("{0}.b64.txt", Gutils.TempDataFile);
            if(!ProcessFile(ms, b64Name))
            {
                return false;
            }
            ds.UploadDocument(b64Name, Gutils.DataFileName);
            if (File.Exists(b64Name)) File.Delete(b64Name);

            return true;
        }

        private static bool ProcessFile(Stream strIn, string b64Name)
        {
            if (strIn == null || strIn == Stream.Null)
            {
                return false;
            }
            using(var strOut = Gutils.EncodeStream(strIn))
            {
                strOut.Seek(0, SeekOrigin.Begin);
                var buff = new byte[strOut.Length];
                using(var fs = File.Create(b64Name))
                {
                    strOut.Read(buff, 0, (int)strOut.Length);
                    fs.Write(buff, 0, buff.Length);
                }
                
            }
            return true;
        }

        #endregion
    }
}
